﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2012-04-13
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


//----------------------------------------------------------------
// 函数体变量自动保护
//----------------------------------------------------------------
template < typename _Ty >
class FUI_AutoVariable
{
public:
    FUI_AutoVariable(_Ty& _oper, _Ty new_vl)
        :oper(&_oper)
        ,save(_oper)
    {
        *oper = new_vl;
    }
    ~FUI_AutoVariable()
    {
        *oper = save;
    }

protected:
    _Ty* oper;
    _Ty save;
};


//----------------------------------------------------------------
// 简单容器，便于 Fuel4D 导出，不依赖STL等相关库
//----------------------------------------------------------------
template < typename _Ty >
class FUI_Vector
{
public:
    typedef FUI_Vector< _Ty >   _MyTy;
    typedef _Ty                 _DataTy;

    FUI_Vector()
        :my_pos(0)
        ,my_capacity(0)
        ,paddr(0)
    {
        paddr = 0;
    }
    FUI_Vector(size_t size)
        :my_pos(0)
        ,my_capacity(0)
        ,paddr(0)
    {
        resize(size);
    }
    ~FUI_Vector()
    {
        release();
    }
    FUI_Vector(const _MyTy& _t)
        :my_pos(0)
        ,my_capacity(0)
        ,paddr(0)
    {
        operator=(_t);
    }
    _Ty* get()
    {
        return paddr;
    }
    _Ty* get() const
    {
        return paddr;
    }
    void operator=(const _MyTy& _r)
    {
        size_t size = _r.size();
        if (size)
        {
            resize(size);
            for (size_t i = 0; i < size; ++i)
                paddr[i] = _r.paddr[i];
        }
        else
            clear();
    }
    void reserve(size_t size)
    {
        size_t t_size = my_pos;
        resize(size);
        my_pos = t_size;
    }
    void resize(size_t size)
    {
        if (size > 0)
        {
            if (my_capacity < size)
                force_reallocte(size);
            my_pos = size;
        }
        else
            my_pos = 0;
    }
    void resize(const _Ty& v, size_t size)
    {
        resize(size);
        for (size_t i = 0; i < size; ++i)
            operator[](i) = v;
    }
    void clear()
    {
        my_pos = 0;
    }
    bool empty() const
    {
        return my_pos == 0;
    }
    _Ty& push_back(const _Ty& k)
    {
        check_allocte(1);
        paddr[my_pos] = k;
        my_pos++;
        return back();
    }
    void append(const _Ty* p, size_t size)
    {
        check_allocte(size);
        for (size_t i = 0; i < size; ++i)
            paddr[my_pos+i] = p[i];
        my_pos += size;
    }
    size_t size() const
    {
        return my_pos;
    }
    size_t capacity() const
    {
        return my_capacity;
    }
    _Ty* begin()
    {
        return paddr;
    }
    _Ty* end()
    {
        if (paddr)
            return paddr + my_pos;
        return 0;
    }
    void release()
    {
        force_delete();
        my_pos = my_capacity = 0;
    }
    _Ty& back() const
    {
        return paddr[my_pos - 1];
    }
    void pop_back()
    {
        if (my_pos > 0)
            my_pos--;
    }
    _Ty& insert(size_t idx, const _Ty& v)
    {
        if (idx >= my_pos || empty())
            return push_back(v);
        else
        {
            check_allocte(1);
            for (int i = (int)my_pos - 1; i >= (int)idx; --i)
                paddr[i+1] = paddr[i];
            paddr[idx] = v;
            my_pos++;
            return paddr[idx];
        }
    }
    bool erase(size_t idx, size_t length = 1)
    {
        if (idx >= my_pos || empty())
            return false;
        if (idx + length > my_pos)
            length = my_pos - idx;
        size_t copy_size = my_pos - idx - length;
        for (size_t i = 0; i < copy_size; ++i)
            paddr[idx+i] = paddr[idx+length+i];
        my_pos -= length;
        return true;
    }
    bool erase(const _Ty& vd)
    {
        for (size_t i = 0; i < my_pos; ++i)
        {
            if (paddr[i] == vd)
                return erase(i, 1);
        }
        return false;
    }
    bool has(const _Ty& vd)
    {
        for (size_t i = 0; i < my_pos; ++i)
        {
            if (paddr[i] == vd)
                return true;
        }
        return false;
    }
    _Ty& operator [](size_t idx) const
    {
        return paddr[idx];
    }

    size_t my_pos, my_capacity;
    _Ty* paddr;

protected:
    void check_allocte(size_t add_n)
    {
        if (my_pos + add_n > my_capacity)
        {
            size_t need_size = FUI_Max(my_pos + add_n, my_capacity);
            if (need_size > 4)
                force_reallocte(need_size + (need_size>>2));
            else
                force_reallocte(4);
        }
    }
    void force_reallocte(size_t size)
    {
        _Ty* new_addr = (_Ty*)FUI_Alloc(BYTE, size * sizeof(_Ty));
        for (size_t i = 0; i < size; ++i)
            FUI_NewPT(new_addr+i, _Ty);
        for (size_t i = 0; i < my_pos; ++i)
            new_addr[i] = paddr[i];
        force_delete();
        paddr = new_addr;
        my_capacity = size;
    }
    void force_delete()
    {
        for (size_t i = 0; i < my_capacity; ++i)
            paddr[i].~_Ty();
        FUI_Free(paddr);
    }
};


//----------------------------------------------------------------
//
//----------------------------------------------------------------
typedef FUI_Vector< ACHAR >            FV_UI_ACHAR;
typedef FUI_Vector< WCHAR >            FV_UI_WCHAR;
typedef FUI_Vector< TCHAR >            FV_UI_TCHAR;
typedef FUI_Vector< FFCHAR >           FV_UI_FFCHAR;
typedef FUI_Vector< bool >             FV_UI_BOOL;
typedef FUI_Vector< BYTE >             FV_UI_BYTE;
typedef FUI_Vector< WORD >             FV_UI_WORD;
typedef FUI_Vector< DWORD >            FV_UI_DWORD;
typedef FUI_Vector< CHAR >             FV_UI_CHAR;
typedef FUI_Vector< SHORT >            FV_UI_SHORT;
typedef FUI_Vector< INT >              FV_UI_INT;
typedef FUI_Vector< LONG >             FV_UI_LONG;
typedef FUI_Vector< INT64 >            FV_UI_INT64;
typedef FUI_Vector< FLOAT >            FV_UI_FLOAT;
typedef FUI_Vector< DOUBLE >           FV_UI_DOUBLE;
typedef FUI_Vector< size_t >           FV_UI_SIZE_T;
typedef FUI_Vector< FIDHASH >          FV_UI_HASH;
typedef FUI_Vector< POINT >            FV_UI_POINT;
typedef FUI_Vector< RECT >             FV_UI_RECT;


//----------------------------------------------------------------
//
//----------------------------------------------------------------
typedef FUI_Vector< bool* >            FV_UI_PBOOL;
typedef FUI_Vector< ACHAR* >           FV_UI_PACHAR;
typedef FUI_Vector< WCHAR* >           FV_UI_PWCHAR;
typedef FUI_Vector< TCHAR* >           FV_UI_PTCHAR;
typedef FUI_Vector< FFCHAR* >          FV_UI_PFFCHAR;
typedef FUI_Vector< BYTE* >            FV_UI_PBYTE;
typedef FUI_Vector< WORD* >            FV_UI_PWORD;
typedef FUI_Vector< DWORD* >           FV_UI_PDWORD;
typedef FUI_Vector< CHAR* >            FV_UI_PCHAR;
typedef FUI_Vector< SHORT* >           FV_UI_PSHORT;
typedef FUI_Vector< INT* >             FV_UI_PINT;
typedef FUI_Vector< LONG* >            FV_UI_PLONG;
typedef FUI_Vector< INT64* >           FV_UI_PINT64;
typedef FUI_Vector< FLOAT* >           FV_UI_PFLOAT;
typedef FUI_Vector< DOUBLE* >          FV_UI_PDOUBLE;
typedef FUI_Vector< size_t* >          FV_UI_PSIZE_T;
typedef FUI_Vector< FIDHASH* >         FV_UI_PHASH;
typedef FUI_Vector< POINT* >           FV_UI_PPOINT;
typedef FUI_Vector< RECT* >            FV_UI_PRECT;